﻿/*
* Copyright (c) 2010-2012 Tesla Engine Group
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

using System;
using Tesla.Math;

namespace Tesla.Content {
    /// <summary>
    /// Interface for a writer that serializes an object that implements the ISavable interface
    /// to an output.
    /// </summary>
    public interface ISavableWriter : IDisposable {

        /// <summary>
        /// Gets or sets if the writer should write external objects, which involves evoking
        /// writers for that type. If false, externals are simply written to the same output.
        /// </summary>
        bool WriteExternals {
            get;
            set;
        }

        /// <summary>
        /// Gets the name of the resource output that the writer will write data to.
        /// </summary>
        String FullResourceName {
            get;
        }

        /// <summary>
        /// Gets if the writer has been disposed or not.
        /// </summary>
        bool IsDisposed {
            get;
        }

        /// <summary>
        /// Causes all outstanding data to be written to their outputs.
        /// </summary>
        void Flush();

        /// <summary>
        /// Registers an external writer to be used by the savable writer when an external
        /// reference is asked to be written for a specific savable type.
        /// </summary>
        /// <param name="writer">External reader</param>
        void RegisterExternalWriter(ExternalWriter writer);

        /// <summary>
        /// Gets an external writer, if it exists, by target type.
        /// </summary>
        /// <param name="targetType">The savable target type.</param>
        /// <returns>The appropiate writer</returns>
        ExternalWriter GetExternalWriter(Type targetType);

        /// <summary>
        /// Removes an external writer by target type.
        /// </summary>
        /// <param name="targetType">Savable target type</param>
        void RemoveExternalWriter(Type targetType);

        /// <summary>
        /// Writes a single byte to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Byte value</param>
        void Write(String name, byte value);

        /// <summary>
        /// Writes an array of bytes to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Array of bytes</param>
        void Write(String name, byte[] value);

        /// <summary>
        /// Writes a 2D array of bytes to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">2D array of bytes</param>
        void Write(String name, byte[,] value);

        /// <summary>
        /// Writes a single sbyte to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">SByte value</param>
        void Write(String name, sbyte value);

        /// <summary>
        /// Writes an array of sbytes to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Array of sbytes</param>
        void Write(String name, sbyte[] value);

        /// <summary>
        /// Writes a 2D array of sbytes to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">2D array of sbytes</param>
        void Write(String name, sbyte[,] value);

        /// <summary>
        /// Writes a single char to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Char value</param>
        void Write(String name, char value);

        /// <summary>
        /// Writes an array of char to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Array of char</param>
        void Write(String name, char[] value);

        /// <summary>
        /// Writes a 2D array of char to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">2D array of char</param>
        void Write(String name, char[,] value);

        /// <summary>
        /// Writes a single unsigned 16-bit int to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">UInt16 value</param>
        void Write(String name, ushort value);

        /// <summary>
        /// Writes an array of unsigned 16-bit ints to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Array of UInt16</param>
        void Write(String name, ushort[] value);

        /// <summary>
        /// Writes a 2D array of unsigned 16-bit ints to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">2D array of UInt16</param>
        void Write(String name, ushort[,] value);

        /// <summary>
        /// Writes a single unsigned 32-bit int to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">UInt32 value</param>
        void Write(String name, uint value);

        /// <summary>
        /// Writes an array of unsigned 32-bit ints to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Array of UInt32</param>
        void Write(String name, uint[] value);

        /// <summary>
        /// Writes a 2D array of unsigned 32-bit ints to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">2D array of UInt32</param>
        void Write(String name, uint[,] value);

        /// <summary>
        /// Writes a single unsigned 64-bit int to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">UInt64 value</param>
        void Write(String name, ulong value);

        /// <summary>
        /// Writes an array of unsigned 64-bit ints to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Array of UInt64</param>
        void Write(String name, ulong[] value);

        /// <summary>
        /// Writes a 2D array of unsigned 64-bit ints to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">2D array of UInt64</param>
        void Write(String name, ulong[,] value);

        /// <summary>
        /// Writes a single 16-bit int to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Int16 value</param>
        void Write(String name, short value);

        /// <summary>
        /// Writes an array of 16-bit ints to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Array of Int16</param>
        void Write(String name, short[] value);

        /// <summary>
        /// Writes a 2D array of 16-bit ints to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">2D array of Int16</param>
        void Write(String name, short[,] value);

        /// <summary>
        /// Writes a single 32-bit int to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Int32 value</param>
        void Write(String name, int value);

        /// <summary>
        /// Writes an array of 32-bit ints to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Array of Int32</param>
        void Write(String name, int[] value);

        /// <summary>
        /// Writes a 2D array of 32-bit ints to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">2D array of Int32</param>
        void Write(String name, int[,] value);

        /// <summary>
        /// Writes a single 64-bit int to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Int64 value</param>
        void Write(String name, long value);

        /// <summary>
        /// Writes an array of 64-bit ints to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Array of Int64</param>
        void Write(String name, long[] value);

        /// <summary>
        /// Writes a 2D array of 64-bit ints to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">2D array of Int64</param>
        void Write(String name, long[,] value);

        /// <summary>
        /// Writes a single float value to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Float value</param>
        void Write(String name, float value);

        /// <summary>
        /// Writes an array of floats to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Array of floats</param>
        void Write(String name, float[] value);

        /// <summary>
        /// Writes a 2D array floats to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">2D array of floats</param>
        void Write(String name, float[,] value);

        /// <summary>
        /// Writes a single double value to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Double value</param>
        void Write(String name, double value);

        /// <summary>
        /// Writes an array of doubles to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Array of doubles</param>
        void Write(String name, double[] value);

        /// <summary>
        /// Writes a 2D array of doubles to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">2D array of doubles</param>
        void Write(String name, double[,] value);

        /// <summary>
        /// Writes a single boolean to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Boolean value</param>
        void Write(String name, bool value);

        /// <summary>
        /// Writes an array of booleans to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Array of booleans</param>
        void Write(String name, bool[] value);
        
        /// <summary>
        /// Writes a 2D array of booleans to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">2D array of booleans</param>
        void Write(String name, bool[,] value);

        /// <summary>
        /// Writes a single string to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">String value</param>
        void Write(String name, String value);

        /// <summary>
        /// Writes an array of strings to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Array of strings</param>
        void Write(String name, String[] value);

        /// <summary>
        /// WRites a 2D array of strings to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">2D array of strings</param>
        void Write(String name, String[,] value);

        /// <summary>
        /// Writes a single color struct to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Color value</param>
        void Write(String name, Color value);

        /// <summary>
        /// Writes an array of color structs to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Array of colors</param>
        void Write(String name, Color[] value);

        /// <summary>
        /// Writes a 2D array of color structs to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">2D array of colors</param>
        void Write(String name, Color[,] value);

        /// <summary>
        /// Writes a single matrix struct to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Matrix value</param>
        void Write(String name, Matrix value);

        /// <summary>
        /// Writes an array of matrix structs to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Array of matrices</param>
        void Write(String name, Matrix[] value);

        /// <summary>
        /// Writes a 2D array of matrix structs to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">2D array of matrices</param>
        void Write(String name, Matrix[,] value);

        /// <summary>
        /// Writes a single quaternion struct to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Quaternion value</param>
        void Write(String name, Quaternion value);

        /// <summary>
        /// Writes an array of quaternion structs to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Array of quaternions</param>
        void Write(String name, Quaternion[] value);

        /// <summary>
        /// Writes a 2D array of quaternion structs to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">2D array of quaternions</param>
        void Write(String name, Quaternion[,] value);

        /// <summary>
        /// Writes a single vector2 struct to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Vector2 value</param>
        void Write(String name, Vector2 value);

        /// <summary>
        /// Writes an array of vector2 structs to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Array of vector2</param>
        void Write(String name, Vector2[] value);

        /// <summary>
        /// Writes a 2D array of vector2 structs to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">2D array of vector2</param>
        void Write(String name, Vector2[,] value);

        /// <summary>
        /// Writes a single vector3 struct to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Vector3 value</param>
        void Write(String name, Vector3 value);

        /// <summary>
        /// Writes an array of vector3 structs to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Array of vector3</param>
        void Write(String name, Vector3[] value);

        /// <summary>
        /// Writes a 2D array of vector3 structs to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">2D array of vector3</param>
        void Write(String name, Vector3[,] value);

        /// <summary>
        /// Writes a single vector4 struct to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Vector4 value</param>
        void Write(String name, Vector4 value);

        /// <summary>
        /// Writes an array of vector4 structs to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Array of vector4</param>
        void Write(String name, Vector4[] value);

        /// <summary>
        /// Writes a 2D array of vector4 structs to the output.
        /// </summary>
        /// <param name="name">Name of the value</param>
        /// <param name="value">2D array of vector4</param>
        void Write(String name, Vector4[,] value);

        /// <summary>
        /// Writes an enum value to the output.
        /// </summary>
        /// <typeparam name="T">Enum type</typeparam>
        /// <param name="name">Name of the value</param>
        /// <param name="enumeration">Enum value</param>
        void WriteEnum<T>(String name, T enumeration) where T : struct;

        /// <summary>
        /// Writes a savable object to the output.
        /// </summary>
        /// <typeparam name="T">Type of object to write</typeparam>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Savable object</param>
        void WriteSavable<T>(String name, T value) where T : ISavable;

        /// <summary>
        /// Writes an array of savable objects to the output.
        /// </summary>
        /// <typeparam name="T">Type of object to write</typeparam>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Array of savables</param>
        void WriteSavable<T>(String name, T[] value) where T : ISavable;

        /// <summary>
        /// Writes a 2D array of savable objects to the output.
        /// </summary>
        /// <typeparam name="T">Type of object to write</typeparam>
        /// <param name="name">Name of the value</param>
        /// <param name="value">2D array of savables</param>
        void WriteSavable<T>(String name, T[,] value) where T : ISavable;

        /// <summary>
        /// Writes a reference to another savable output that is external to this output. Externals
        /// may or may not be written separately, such as there exists no writer for the savable type.
        /// In this case, the external is in fact written as a regular savable object to the same stream.
        /// </summary>
        /// <typeparam name="T">Type of object to write</typeparam>
        /// <param name="name">Name of the value</param>
        /// <param name="value">Savable object</param>
        void WriteExternal<T>(String name, T value) where T : ISavable;
    }
}
